package social.server.main;

import java.util.Date;
import java.util.Vector;

import social.server.Exceptions.InexistentReceiverException;
import social.server.Exceptions.InexistentTopicException;
import social.server.Exceptions.InvalidIdSessionException;
import social.server.Exceptions.InvalidMessageException;
import social.server.Exceptions.InvalidReceiverException;
import social.server.Exceptions.InvalidSubjectException;
import social.server.Exceptions.InvalidTopicIdException;
import social.server.Exceptions.NoIdSessionFoundException;

public class MessageManager {

	private  Vector<Inbox> vector = new Vector<Inbox>();

	private static final MessageManager instance = new MessageManager();
	
	/**
	 * Retorna a unica instancia da classe.
	 * 
	 * @return Um objeto MessageManager.
	 */
	public static MessageManager getInstance() {
		return instance;
	}
	/**
	 * Esse método retorna a Inbox de um usuário.
	 * @param owner Esse argumento é o login do dono da Inbox.
	 * @return Retorna a Inbox do usuário.
	 */
	private Inbox getUserInbox(String owner) {
		for (int i = 0; i < vector.size(); i++) {
			if (vector.get(i).getOwner().equals(owner))
				return vector.get(i);
		}
		addInbox(owner);
		return getUserInbox(owner);
	}
	/**
	 * Esse método manda uma mensagem de um usuário para outro. Ele cria uma nova thread se nenhuma
	 * thread com esse assunto existir, ou se já existe uma thread com esse assunto, ele coloca a
	 * nova mensagem no topo das postagens dessa thread.
	 * @param userId É o login do primeiro usuário.
	 * @param userId2 É o login do segundo usuário.
	 * @param subject É o assunto da mensagem.
	 * @param message É a mensagem.
	 * @param requestId É o número de requisição caso ele exista. Se houver um número de requisição
	 * a mensagem será marcada como "negociação", caso não haja, ela será marcada como offtopic.
	 * @throws InvalidIdSessionException Caso o login do remetente seja vazio ou nulo.
	 * @throws NoIdSessionFoundException Caso o login do remetente não esteja registrado no sistema.
	 * @throws InvalidReceiverException Caso o login do destinatário seja vazio ou nulo.
	 * @throws InexistentReceiverException Caso o login do destinatário não esteja registrado no sistema.
	 * @throws InvalidSubjectException Caso o assunto seja vazio ou nulo.
	 * @throws InvalidMessageException Caso a mensagem seja vazia ou nula.
	 */
	public void addInbox(String owner) {
		vector.add(new Inbox(owner));
	}

	public void sendMessage(String userId, String userId2, String subject,
			String message)  {
		
		
		Inbox inbox1 = getUserInbox(userId);
		Inbox inbox2 = getUserInbox(userId2);
		
		Post newPost = new Post(userId, message, new Date());
		
		if (!inbox1.containsThread(subject)){
			Thread newThread = new Thread(subject, userId, userId2);
			newThread.add(newPost);
			inbox1.addThread(newThread);
		}
		else{
			inbox1.getThread(subject).add(newPost);
			inbox1.reorganize(subject);
		}
		if (!inbox2.containsThread(subject)){
			Thread newThread = new Thread(subject, userId, userId2);
			newThread.add(newPost);
			inbox2.addThread(newThread);
		}
		else{
			inbox2.getThread(subject).add(newPost);
			inbox2.reorganize(subject);
		}
	}
	
	public void sendMessage(String userId, String userId2, String subject,
			String message, String requestId)  {
		
		
		Inbox inbox1 = getUserInbox(userId);
		Inbox inbox2 = getUserInbox(userId2);
		
		Post newPost = new Post(userId, message, new Date());
		
		if (!inbox1.containsThread(subject)){
			NegotiationThread newThread = new NegotiationThread(subject, userId, userId2, requestId);
			newThread.add(newPost);
			inbox1.addThread(newThread);
		}
		else{
			inbox1.getThread(subject).add(newPost);
			inbox1.reorganize(subject);
		}
		if (!inbox2.containsThread(subject)){
			NegotiationThread newThread = new NegotiationThread(subject, userId, userId2, requestId);
			newThread.add(newPost);
			inbox2.addThread(newThread);
		}
		else{
			inbox2.getThread(subject).add(newPost);
			inbox2.reorganize(subject);
		}
	}
	/**
	 * Esse método verifica se uma thread já existe na Inbox de um usuário.
	 * @param userId Login do usuário.
	 * @param subject Assunto da thread.
	 * @return true caso exista, false caso não exista.
	 */
	public boolean containsThread(String userId, String subject) {
		Inbox inbox1 = getUserInbox(userId);
		return inbox1.containsThread(subject);
	}

	/**
	 * Esse método retorna uma lista de Threads organizada por tipos.
	 * @param userId O login do dono da inbox que de onde se quer obter a lista.
	 * @param type O tipo de pesquisa: All, Negotiation ou OffTopic.
	 * @return Retorna uma string que é a lista ou uma mensagem de erro caso nada tenha sido encontrado.
	 * @throws InvalidIdSessionException Caso o login do remetente seja vazio ou nulo.
	 * @throws NoIdSessionFoundException Caso o login do remetente não esteja registrado no sistema.
	 */
	public String getThreadList(String userId, String type){
		Inbox inbox1 = getUserInbox(userId);
		return inbox1.getThreadList(type);
	}
	/**
	 * Esse método retorna uma thread específica na Inbox de um usuário.
	 * @param userId Login do usuário.
	 * @param subject Assunto da thread.
	 * @return Retorna uma string com as mensagens thread pesquisada.
	 * @throws InvalidIdSessionException Caso o login do remetente seja vazio ou nulo.
	 * @throws NoIdSessionFoundException Caso o login do remetente não esteja registrado no sistema.
	 * @throws InvalidTopicIdException Quando o assunto da thread é nulo ou vazio.
	 * @throws InexistentTopicException Quando a thread não existe.
	 */
	public String getThread(String userId, String subject) throws InexistentTopicException{	
		Inbox inbox1 = getUserInbox(userId);
		String toReturn = inbox1.getThreadString(subject);
		if (toReturn == null){
			throw new InexistentTopicException();
		}
		return toReturn;
	}
}